﻿using System;
using System.IO;
using System.Text;
using System.Collections.Generic;
using MiscUtil.Conversion;

namespace Network
{
    public class TcpStreamCoDec
    {
        //接收数据
        byte[] _splitBuff;
        int _curSplitPos;

        //发送数据
        //发送队列
        Queue<byte[]> _sendMsg;
        Queue<byte[]> _recvMsg;
        byte[] _sendingBytes;//正在发送数据
        int _leftSendingBytes;//正在发送数据长度

        const int msgLengthSize = 2;

        public TcpStreamCoDec()
        {
            _splitBuff = new byte[1024];
            _curSplitPos = 0;

            _sendMsg = new Queue<byte[]>();
            _recvMsg = new Queue<byte[]>();

            _sendingBytes = new byte[1024];
            _leftSendingBytes = 0;
        }

        public void Decode(byte[] recvBuffer, int recvLen)
        {
            if (recvLen == 0)
                return;

            if (_curSplitPos + recvLen > _splitBuff.Length)
            {
                byte[] newBuff = new byte[_curSplitPos + recvLen];
                Array.Copy(_splitBuff, 0, newBuff, 0, _splitBuff.Length);
                _splitBuff = newBuff;
            }

            Array.Copy(recvBuffer, 0, _splitBuff, _curSplitPos, recvLen);
            _curSplitPos += recvLen;

            while (true)
            {
                if (_curSplitPos < msgLengthSize)
                {
                    break;
                }

                MemoryStream msgStream = new MemoryStream(_splitBuff, 0, _curSplitPos);
                BinaryReader reader = new BinaryReader(msgStream, Encoding.Unicode);
                byte[] data = reader.ReadBytes(msgLengthSize);
                int msgLen = EndianBitConverter.Big.ToInt16(data, 0);

                if (_curSplitPos >= msgLen + msgLengthSize)
                {
                    data = reader.ReadBytes(msgLen);
                    _curSplitPos -= (msgLen + msgLengthSize);
                    MemMove(_splitBuff, msgLen + msgLengthSize, 0, _curSplitPos);
                    _recvMsg.Enqueue(data);
                }
                else
                {
                    break;
                }
            }
        }

        public byte[] GetReceivedObject()
        {
            return _recvMsg.Count > 0 ? _recvMsg.Dequeue() : null;
        }

        public void Encode(byte[] data)
        {
            _sendMsg.Enqueue(data);
        }

        public int GetSendingBytes(out byte[] bytes)
        {
            if (_leftSendingBytes == 0)
            {
                if (_sendMsg.Count > 0)
                {
                    byte[] msg = _sendMsg.Dequeue();
                    _leftSendingBytes = encodeStream(msg);
                }
            }

            bytes = _sendingBytes;
            return _leftSendingBytes;
        }

        public void FinishSendingBytes(int len)
        {
            _leftSendingBytes -= len;
            MemMove(_sendingBytes, len, 0, _leftSendingBytes);
        }

        int encodeStream(byte[] data)
        {
            int bufSize;
            if (data == null)
            {
                bufSize = 0;
            }
            else
            {
                bufSize = data.Length;
            }

            int size = bufSize + msgLengthSize;

            if (_sendingBytes.Length < size)
                _sendingBytes = new byte[size];

            EndianBitConverter.Big.GetBytes((short)bufSize).CopyTo(_sendingBytes, 0);
            if (data != null)
            {
                data.CopyTo(_sendingBytes, msgLengthSize);
            }

            return size;
        }

        static void MemMove(byte[] buff, int sourceIndex, int destIndex, int len)
        {
            for (int i = 0; i < len; ++i)
            {
                buff[i + destIndex] = buff[i + sourceIndex];
            }
        }
    }

}
